#include "helper.h"
#include "monitor.h"
#include "reg.h"

extern uint32_t instr;
extern char assembly[80];
extern FILE *fp;
/* decode I12-type instrucion with unsigned immediate */
static void decode_ui12_type(uint32_t instr)
{

	op_src1->type = OP_TYPE_REG;
	op_src1->reg = (instr >> 5) & 0x0000001F;
	op_src1->val = reg_w(op_src1->reg);

	op_src2->type = OP_TYPE_IMM;
	op_src2->imm = (instr >> 10) & 0x00000FFF;
	op_src2->val = op_src2->imm;

	op_dest->type = OP_TYPE_REG;
	op_dest->reg = instr & 0x0000001F;
}

make_helper(ori)
{

	decode_ui12_type(instr);
	reg_w(op_dest->reg) = op_src1->val | op_src2->val;
	sprintf(assembly, "ori\t%s,\t%s,\t0x%03x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
	fprintf(fp, "%08x\t%s\t0x%08x\n", pc | 0x80000000, REG_NAME(op_dest->reg), reg_w(op_dest->reg));
}

make_helper(sltui)
{
	decode_ui12_type(instr);
	uint32_t imm_val = (op_src2->val >> 11) ? (op_src2->val | 0xFFFFF000) : op_src2->val;
	reg_w(op_dest->reg) = (op_src1->val < imm_val) ? 1 : 0;
	sprintf(assembly, "sltui\t%s,\t%s,\t0x%03x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
	fprintf(fp, "%08x\t%s\t0x%08x\n", pc | 0x80000000, REG_NAME(op_dest->reg), reg_w(op_dest->reg));
}

make_helper(addi_w)
{
	decode_ui12_type(instr);
	uint32_t imm_val = (op_src2->val >> 11) ? (op_src2->val | 0xFFFFF000) : op_src2->val;
	reg_w(op_dest->reg) = op_src1->val + imm_val;
	sprintf(assembly, "addi.w\t%s,\t%s,\t0x%03x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
	fprintf(fp, "%08x\t%s\t0x%08x\n", pc | 0x80000000, REG_NAME(op_dest->reg), reg_w(op_dest->reg));
}

make_helper(andi)
{
	decode_ui12_type(instr);
	reg_w(op_dest->reg) = op_src1->val & op_src2->val;
	sprintf(assembly, "andi\t%s,\t%s,\t0x%03x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
	fprintf(fp, "%08x\t%s\t0x%08x\n", pc | 0x80000000, REG_NAME(op_dest->reg), reg_w(op_dest->reg));
}

make_helper(ld_b)
{
	decode_ui12_type(instr);
	uint32_t imm_val = (op_src2->val >> 11) ? (op_src2->val | 0xFFFFF000) : op_src2->val;
	uint32_t addr = (op_src1->val + imm_val) & 0x7FFFFFFF;
	uint32_t result_b = mem_read(addr, 1);
	reg_w(op_dest->reg) = (result_b >> 7) ? (result_b | 0xFFFFFF00) : (result_b & 0x000000FF);
	sprintf(assembly, "ld.b\t%s,\t%s,\t0x%03x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
	fprintf(fp, "%08x\t%s\t0x%08x\n", pc | 0x80000000, REG_NAME(op_dest->reg), reg_w(op_dest->reg));
}

make_helper(ld_w)
{
	decode_ui12_type(instr);
	uint32_t imm_val = (op_src2->val >> 11) ? (op_src2->val | 0xFFFFF000) : op_src2->val;
	uint32_t addr = (op_src1->val + imm_val) & 0x7FFFFFFF;
	uint32_t result_w = mem_read(addr, 4);
	reg_w(op_dest->reg) = result_w;
	sprintf(assembly, "ld.w\t%s,\t%s,\t0x%03x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
	fprintf(fp, "%08x\t%s\t0x%08x\n", pc | 0x80000000, REG_NAME(op_dest->reg), reg_w(op_dest->reg));
}

make_helper(st_b)
{
	decode_ui12_type(instr);
	uint32_t imm_val = (op_src2->val >> 11) ? (op_src2->val | 0xFFFFF000) : op_src2->val;
	uint32_t addr = (op_src1->val + imm_val) & 0x7FFFFFFF;
	uint32_t result_b = reg_w(op_dest->reg) & 0xFF;
	mem_write(addr, 1, result_b);
	sprintf(assembly, "st.b\t%s,\t%s,\t0x%03x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
}

make_helper(st_w)
{
	decode_ui12_type(instr);
	uint32_t imm_val = (op_src2->val >> 11) ? (op_src2->val | 0xFFFFF000) : op_src2->val;
	uint32_t addr = (op_src1->val + imm_val) & 0x7FFFFFFF;
	uint32_t result_w = reg_w(op_dest->reg);
	mem_write(addr, 4, result_w);
	sprintf(assembly, "st.w\t%s,\t%s,\t0x%03x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
}